﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Entity;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using SailHero.Soft.FrameWork.DAO.Contracts;
using SailHero.Soft.FrameWork.DAO.Data.Extenstions;

namespace SailHero.Soft.FrameWork.DAO.Core
{
    public class EFRepository<TEntity> : IRepository<TEntity> where TEntity : class
    {
        private readonly string _connectionStringName;
        private DbContext _dbContext;
        private IUnitOfWork _baseCore;

        public EFRepository(string connectionStringName)
        {
            _connectionStringName = connectionStringName;
        }

        public void UpdateRef<TEntity>(TEntity source, ref TEntity New, params string[] ignores)
        {
            Type info = typeof(TEntity);
            PropertyInfo[] propertys = info.GetProperties();

            foreach (PropertyInfo pi in propertys)
            {
                if (ignores.Contains(pi.Name))
                    continue;
                info.GetProperty(pi.Name).SetValue(New, pi.GetValue(source, null), null);
            }
        }

        public DbContext DbContext
        {
            get
            {
                if (_dbContext == null)
                {
                    if (string.IsNullOrEmpty(_connectionStringName))
                        throw new Exception("_connectionStringName不能为空");
                    _dbContext = DbContextManager.CurrentByKey(_connectionStringName);
                }
                return _dbContext;
            }
        }

        #region Implementation of IRepository<TEntity>

        /// <summary>
        /// 获取IQueryable
        /// </summary>
        /// <returns>IQueryable</returns>
        public IQueryable<TEntity> GetQuery()
        {
            return DbContext.Set<TEntity>();
        }

        /// <summary>
        /// 根据条件获取IQueryable
        /// </summary>
        /// <param name="predicate">查询条件表达式</param>
        /// <returns>IQueryable</returns>
        public IQueryable<TEntity> GetQuery(Expression<Func<TEntity, bool>> predicate)
        {
            return DbContext.Set<TEntity>().Where(predicate);
        }

        /// <summary>
        /// 根据主键属性得到实体
        /// </summary>
        /// <param name="objectId">主键属性值</param>
        /// <returns>实体</returns>
        public TEntity Get(object objectId)
        {
            return DbContext.Set<TEntity>().Find(objectId);
        }

        /// <summary>
        /// 根据条件获取唯一的实体
        /// </summary>
        /// <param name="predicate">查询条件表达式</param>
        /// <returns>实体</returns>
        public TEntity SingleOrDefault(Expression<Func<TEntity, bool>> predicate)
        {
            return DbContext.Set<TEntity>().SingleOrDefault(predicate);
        }

        /// <summary>
        /// 根据条件获取第一条实体
        /// </summary>
        /// <param name="predicate">查询条件表达式</param>
        /// <returns>实体</returns>
        public TEntity FirstOrDefault(Expression<Func<TEntity, bool>> predicate)
        {
            return DbContext.Set<TEntity>().FirstOrDefault(predicate);
        }

        /// <summary>
        /// 根据条件获取列表
        /// </summary>
        /// <param name="predicate">查询条件表达式</param>
        /// <returns>实体列表</returns>
        public IEnumerable<TEntity> GetList(Expression<Func<TEntity, bool>> predicate)
        {
            return DbContext.Set<TEntity>().Where(predicate);
        }
        /// <summary>
        /// 根据条件获取列表
        /// </summary>
        /// <param name="predicate">查询条件表达式</param>
        /// <returns>实体列表</returns>
        public IEnumerable<TEntity> GetAllList()
        {
            return DbContext.Set<TEntity>();
        }
        /// <summary>
        /// 根据条件获取分页列表
        /// </summary>
        /// <param name="predicate">查询条件表达式</param>
        /// <param name="orderBy">排序字段</param>
        /// <param name="ascending">是否顺序</param>
        /// <param name="pageIndex">页索引</param>
        /// <param name="pageSize">页大小</param>
        /// <returns>实体分页列表</returns>
        public PagedList<TEntity> GetPagedList(Expression<Func<TEntity, bool>> predicate, string orderBy, bool @ascending, int pageIndex, int pageSize)
        {
            return DbContext.Set<TEntity>().Where(predicate).OrderBy(orderBy, ascending).ToPagedList(pageIndex, pageSize);
        }

        /// <summary>
        /// 新增实体
        /// </summary>
        /// <param name="entity">实体</param>
        public void Add(TEntity entity)
        {
            DbContext.Set<TEntity>().Add(entity);
        }

                

        /// <summary>
        /// 删除实体
        /// </summary>
        /// <param name="entity">实体</param>
        public void Delete(TEntity entity)
        {
            DbContext.Set<TEntity>().Remove(entity);
        }

        /// <summary>
        /// 根据条件删除
        /// </summary>
        /// <param name="predicate">查询条件表达式</param>
        public void Delete(Expression<Func<TEntity, bool>> predicate)
        {
            var list = DbContext.Set<TEntity>().Where(predicate);
            foreach (var entity in list)
            {
                DbContext.Set<TEntity>().Remove(entity);
            }
        }

        /// <summary>
        /// 获取总数
        /// </summary>
        /// <returns>总数</returns>
        public int Count()
        {
            return DbContext.Set<TEntity>().Count();
        }

        /// <summary>
        /// 根据条件获取总数
        /// </summary>
        /// <param name="predicate">查询条件表达式</param>
        /// <returns>总数</returns>
        public int Count(Expression<Func<TEntity, bool>> predicate)
        {
            return DbContext.Set<TEntity>().Count(predicate);
        }
        /// <summary>
        /// 根据存储过程名及参数获取数据 
        /// </summary>
        /// <param name="spName">存储过程名</param>
        /// <returns>存储过程返回的数据</returns>
        public IEnumerable<TEntity> GetDataBySp(string sp)
        {
            return DbContext.Database.SqlQuery<TEntity>(sp);
        }
        /// <summary>
        /// 工作单元
        /// </summary>
        public IUnitOfWork UnitOfWork
        {
            get { return _baseCore ?? (_baseCore = new UnitOfWork(this.DbContext)); }
        }

        #endregion
    }
}